using System;
using System.Collections.Generic;

namespace CsharpPoker
{
    public class TexasHoldemEngine 
    {
        public enum States { setup = 0, preflop, flop, turn, river, end }
        public enum PlayerActions { none = 0, fold, check, call, bet, raise, allin }
        public static int NoCard = 55; // represents a placeholder card.

        // a texas holdem player
        public class Player
        {
            private int[] myHand;
            PlayerActions myAction;

            public Player()
            {
                myHand = new int[2];
                myAction = PlayerActions.none;
            }

            public int[] Cards
            {
                get { return myHand; }
            }

            public PlayerActions Action
            {
                get { return myAction; }

                set { myAction = value; }
            }
            
        }

        // texas holdem data ----------------------------------------------- //

        private States state; // keeps track of the texas holdem game state.

        private int[] deck;
        private int   deckIdx; // index for top of the deck.
        private List<int>  burns;
         
        private int[] communityCards;
        
        private Player player;

        bool processInput = false;

        // texas holdem functionality -------------------------------------- //

        // Constructor
        public TexasHoldemEngine()
        {
            state = States.setup;
        }

        public void Run()
        {
            if (processInput)
            {
                ProcessPlayerAction();
            }
            else
            {
                switch (state)
                {
                    case States.setup: Setup(); break;

                    case States.preflop: Preflop(); break;

                    case States.flop: Flop(); break;

                    case States.turn: Turn(); break;

                    case States.river: River(); break;

                    default: 
                        return; 
                }

                // After calling a game state function we being procesing all players input.
                processInput = true;
            }
        }

        public void ProcessPlayerAction()
        {
            switch (player.Action)
            {
                case PlayerActions.check:
                    {
                    } break;

                case PlayerActions.fold:
                    {
                    } break;
                
                default: break;
            }

            // If all the players have taken action, then going to the next phase of the game.
            if (player.Action != PlayerActions.none)
            {
                // reset player actions
                player.Action = PlayerActions.none;
               
                // reset input processing
                processInput = false;
                
                State++; // go to the next state. i.e. from preflopInput to flop
            }
        }

        void Burn()
        {
            burns.Add(deck[deckIdx]); // record burned card
            deckIdx++; // increment the top of the deck index
        }

        private void Shuffle()
        {
            // pick cards from random and swap them with the last card.
            Random rnd = new Random();

            for (int i = deck.Length - 1; i >= 0; i--)
            {
                int r = rnd.Next(0, i + 1);

                int tmp = deck[i];
                deck[i] = deck[r];
                deck[r] = tmp;
            }
        }

        // game phases ( Setup, Preflop, Flop, Turn River )

        public void Setup() 
        {
            burns = new List<int>();
            deck = new int[52];

            for (int i = 0; i < 52; ++i)
            {
                deck[i] = i;
            }

            communityCards = new int[5];

            for (int i = 0; i < 5; ++i)
            {
                communityCards[i] = NoCard;
            }

            player = new Player();

            Shuffle();
            deckIdx = 0;
            //wantingUserInput = false;

            // switch to preflop phase of game.
            State = States.preflop;
        }

        public void Preflop() 
        {
            // deal first card
            player.Cards[0] = deck[deckIdx];
            deckIdx++;

            // deal second card
            player.Cards[1] = deck[deckIdx];
            deckIdx++;

            processInput = true;
        }

        public void Flop() 
        { 
            // burn a card
            Burn();
           
            // deal out three community cards;
            communityCards[0] = deck[deckIdx];
            communityCards[1] = deck[deckIdx + 1];
            communityCards[2] = deck[deckIdx + 2];
            deckIdx += 3;
        }
        
        public void Turn() 
        {
            Burn();

            // deal out a community card
            communityCards[3] = deck[deckIdx];
            
            deckIdx++;
        }
        
        public void River() 
        {
            Burn();

            // deal out community card
            communityCards[4] = deck[deckIdx];
            deckIdx++;        
        }
    
        // accessors ------------------------------------------------------- //

        public int[] Deck
        {
            get { return deck; }
        }

        public int DeckIdx
        {
            get { return deckIdx; }
        }

        public int[] CommunityCard
        {
            get { return communityCards; }
        }

        public States State
        {
            get 
            { 
                return state; 
            }

            set
            {
                state = value;

                // reset player actions after game phase switch.
                Player1.Action = PlayerActions.none;
            }
        }

        public Player Player1
        {
            get { return player; }
        }

        public List<int> Burns
        {
            get { return burns; }
        }
    }
}